package com.xjm.service.serviceImpl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjm.config.AppConfig;
import com.xjm.constant.AppConst;
import com.xjm.entity.dto.FileDto;
import com.xjm.entity.model.FileModel;
import com.xjm.entity.vo.FileVo;
import com.xjm.excption.AppException;
import com.xjm.mapper.FileMapper;
import com.xjm.utils.RedisUtil;
import com.xjm.service.FileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

@Service
@Slf4j
@RequiredArgsConstructor
public class FileServiceImpl extends ServiceImpl<FileMapper, FileModel> implements FileService {

    private final RedisUtil redisUtil;

    private final AppConfig appConfig;

    private final FileMapper fileMapper;

    private static final String FILE_PREFIX = AppConst.FILE_KEY;

    @Override
    public FileVo uploadChunk(FileDto dto) {
        String key = FILE_PREFIX + dto.getMd5();
        //分块大小
        long chunkSize = appConfig.getChunkSize();
        //todo 后期补上一个定时任务删除超时的碎片 大概逻辑，每天晚上检测剩余时间是否只剩等于小于一天，然后根据文件名删除
        if (dto.getIndex() == 0 && dto.getTotal() != 1) {
            redisUtil.set(key, 0, 60 * 60 * 24 * 3);
        }
        //后缀
        String suffix = dto.getFileName().substring(dto.getFileName().lastIndexOf("."));
        //先创建临时文件
        String tempName = dto.getMd5().substring(0, 10);

        File temFile = new File(appConfig.getSavePath() + "part/" + tempName);

        try {
            if (!temFile.getParentFile().exists()) {
                if (temFile.getParentFile().mkdirs()) {
                    log.info("创建文件夹成功:" + temFile.getParentFile());
                }
            }
            //偏移值
            long offset = chunkSize * dto.getIndex();
            try (RandomAccessFile raf = new RandomAccessFile(temFile, "rw")) {
                raf.seek(offset);
                raf.write(dto.getFile().getBytes());
            }
        } catch (IOException e) {
            throw new AppException(e.getMessage());

        }
        if (dto.getTotal() != 1) {
            redisUtil.set(key, dto.getIndex(), redisUtil.getExpire(key));
        }
        String realPath = appConfig.getSavePath() + tempName + suffix;
        //是否最后一个块
        if (dto.getIndex() >= dto.getTotal() - 1) {
            // 移动文件
            if (!temFile.renameTo(new File(realPath))) {
                throw new AppException("文件保存失败");
            }

            tempName = tempName + suffix;

            FileModel model = new FileModel();
            model.setMd5(dto.getMd5());
            model.setName(dto.getFileName().length() > 10 ? dto.getFileName().substring(0, 10) : dto.getFileName());
            model.setSize(dto.getSize());
            model.setUrl(appConfig.getUrlMapping() + tempName);
            model.setUserId(StpUtil.getLoginIdAsInt());
            model.setStatus(1);
            model.setSuffix(suffix);
            model.setAbsolutePath(realPath);

            addFile(model);
            redisUtil.delete(key);
            FileVo fileVo = new FileVo();
            BeanUtil.copyProperties(model, fileVo);
            return fileVo;
        }
        return null;
    }


    /**
     * 添加文件
     */
    private void addFile(FileModel fileModel) {
        fileMapper.insert(fileModel);
    }

    /**
     * 检查文件是否存在
     */
    @Override
    public FileVo checkFile(String md5) {
        String key = FILE_PREFIX + md5;
        FileVo fileVo = new FileVo();
        if (redisUtil.hasKey(key)) {
            fileVo.setIndex((Integer) redisUtil.get(key));
            return fileVo;
        }
        LambdaQueryWrapper<FileModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileModel::getMd5, md5);
        FileModel fileModel = fileMapper.selectOne(queryWrapper);
        if (fileModel != null) {
            BeanUtil.copyProperties(fileModel, fileVo);
        }
        return fileVo;
    }

    /**
     * 删除文件
     *
     * @param id 文件id
     */
    @Override
    public void delFile(Long id) {
        FileModel fileModel = fileMapper.selectById(id);
        if (fileModel == null) {
            throw new AppException("文件不存在");
        }
        File file = new File(fileModel.getAbsolutePath());
        if (file.exists()) {
            file.delete();
        }
        fileMapper.deleteById(id);
    }
}
